﻿using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using Interfaces;
using Model;

namespace Controller
{
    [Serializable]
    public class TurneringsSystem
    {
        #region Attributes
        [NonSerialized]
        private DBFacade dbFacade;
        private bool databaseforbindelse;
        private TurneringsCollection turneringsCollection;
        private Turnering aktuelTurnering;
        private Deltager aktuelDeltager;
        private Runde aktuelRunde;
        private int deltagerID = 0;
        private int turneringsID = 0;
        private int rundeID = 0;
        private Random random;
        private const string FILNAVN = "DataLokal.bin";
        #endregion

        #region Konstruktør
        public TurneringsSystem()
        {
            dbFacade = new DBFacade(this);
            turneringsCollection = new TurneringsCollection();
            random = new Random();
        }
        #endregion

        #region Methods
        public void GemData()
        {
            FileStream fileStream = new FileStream(FILNAVN, FileMode.Create, FileAccess.Write);
            BinaryFormatter binFormatter = new BinaryFormatter();
            binFormatter.Serialize(fileStream, turneringsCollection);
            fileStream.Close();
        }

        public void HentData()
        {
            FileStream filestream;
            try
            {
                filestream = new FileStream(FILNAVN, FileMode.Open, FileAccess.Read);
            }
            catch (Exception)
            {
                return;
            }

            BinaryFormatter binFormatter = new BinaryFormatter();
            turneringsCollection = (TurneringsCollection)binFormatter.Deserialize(filestream);
            filestream.Close();

            foreach (Turnering midlertidigTurnering in turneringsCollection.ListeTurneringer)
            {
                if (midlertidigTurnering.TurneringsID < turneringsID)
                {
                    turneringsID = midlertidigTurnering.TurneringsID;
                }
                foreach (Deltager midlertidigDeltager in midlertidigTurnering.ListeDeltagere)
                {
                    if (midlertidigDeltager.DeltagerID < deltagerID)
                    {
                        deltagerID = midlertidigDeltager.DeltagerID;
                    }
                    foreach (Runde midlertidigRunde in midlertidigDeltager.ListeRunde)
                    {
                        if (midlertidigRunde.RundeID < rundeID)
                        {
                            rundeID = midlertidigRunde.RundeID;
                        }
                    }
                }
            }
        }

        public int RandomNumber(int min, int max)
        {
            return random.Next(min, max + 1);
        }

        public int OptældFarve(int deltagerID)
        {
            int SortTæller = 0;
            FindDeltager(deltagerID);
            List<Runde> listeRunde = aktuelDeltager.ListeRunde;

            foreach (Runde nuværendeRunde in listeRunde)
            {
                if (nuværendeRunde.Farve == 0)
                {
                    SortTæller++;
                }
            }
            return SortTæller;
        }

        public void SorterDeltagereTilfældigt()
        {
            int deltagerID;
            // Angiver en midlertidig placering på deltagerne
            int nyPlacering = 0;
            int AntalSpiller = 0;
            IDeltager deltagerdata;
            IEnumerator deltageriterator = aktuelTurnering.GetDeltagerIterator();

            deltageriterator.Reset();

            // Forhver spiler gøres følgende
            while (deltageriterator.MoveNext())
            {
                // Henter deltager over
                deltagerdata = (IDeltager)deltageriterator.Current;
                deltagerID = deltagerdata.DeltagerID;

                // Midlertidig placering bliver tildelt til deltager 
                FlytDeltager(deltagerID, nyPlacering);

                // Optæller antal deltager
                AntalSpiller++;
            }

            deltageriterator.Reset();
            int[] TalArray = new int[AntalSpiller];
            int o = 0;
            while (deltageriterator.MoveNext())
            {
                bool talFindes = false;

                // Udtrækker tal fra 0 til x antalspiller
                int UdtrukketTal = RandomNumber(1, AntalSpiller);
                int i = 0;

                // Så længe false, gør det her og i er mindre end AntalSpiller:
                while (!talFindes && i < AntalSpiller)
                {
                    // Hvis udtreukket tal findes på TalArray, så udtrækkes nyt tal og i sættes til 0
                    if (UdtrukketTal == TalArray[i])
                    {
                        UdtrukketTal = RandomNumber(1, AntalSpiller);
                        i = 0;
                    }
                    else
                    {
                        // Hvis antal gennemløb gennem array er det samme som antal spiller, sættes tal Findes til true.
                        // Hvor med while lykken brydes.
                        if (i == AntalSpiller)
                        {
                            talFindes = true;
                        }
                        else
                        {
                            i++;
                        }
                    }
                }

                // Indsætter det udtrukket tal på Array
                TalArray[o] = UdtrukketTal;
                o++;

                // Angiver hvilken spiller det er
                deltagerdata = (IDeltager)deltageriterator.Current;
                deltagerID = deltagerdata.DeltagerID;

                nyPlacering = UdtrukketTal;
                FlytDeltager(deltagerID, nyPlacering);
                FindDeltager(deltagerID);
                RedigerRunde(1, 0, 0, 0, 0, nyPlacering);
            }
        }
        #endregion

        #region Turnering
        public ITurnering TilføjTurnering(string turneringsnavn, string gruppenavn, DateTime startdato, int antalRunder, int turneringsid = 0)
        {
            if (databaseforbindelse == true)
            {
                try
                {
                    if (turneringsid == 0)
                    {
                        turneringsID = dbFacade.TilføjTurnering(turneringsnavn, gruppenavn, startdato, antalRunder);
                    }
                    else
                    {
                        turneringsID = turneringsid;
                    }
                    if (turneringsID > 0)
                    {
                        aktuelTurnering = turneringsCollection.TilføjTurnering(turneringsnavn, gruppenavn, startdato, antalRunder, turneringsID);
                    }
                    else
                    {
                        aktuelTurnering = null;
                    }
                }
                catch
                {
                    aktuelTurnering = null;
                }
            }
            else
            {
                turneringsID--;
                aktuelTurnering = turneringsCollection.TilføjTurnering(turneringsnavn, gruppenavn, startdato, antalRunder, turneringsID);
            }
            return (ITurnering)aktuelTurnering;
        }

        public bool RedigerTurnering(string navn, string gruppenavn, DateTime startdato, int antalRunder)
        {
            if (databaseforbindelse == true)
            {
                try
                {
                    bool succes = dbFacade.RedigerTurnering(navn, gruppenavn, startdato, antalRunder, aktuelTurnering.TurneringsID);
                    if (succes == true)
                    {
                        turneringsCollection.RedigerTurnering(aktuelTurnering, navn, gruppenavn, startdato, antalRunder);
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                catch
                {
                    return false;
                }
            }
            else
            {
                turneringsCollection.RedigerTurnering(aktuelTurnering, navn, gruppenavn, startdato, antalRunder);
                return true;
            }
        }

        public bool SletTurnering(int turneringsID)
        {
            Turnering turnering = turneringsCollection.FindTurnering(turneringsID);

            if (databaseforbindelse == true)
            {
                bool succes;
                List<Deltager> deltagere = turnering.ListeDeltagere;
                foreach (Deltager nuværendeDeltager in deltagere)
                {
                    succes = dbFacade.FjernDeltager(nuværendeDeltager.DeltagerID);
                    if (succes == false)
                    {
                        return false;
                    }
                }
                succes = dbFacade.FjernTurnering(turneringsID);
                if (succes == true)
                {
                    turneringsCollection.SletTurnering(turnering);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                turneringsCollection.SletTurnering(turnering);
                return true;
            }
        }

        public ITurnering FindTurnering(int turneringsID)
        {
            aktuelTurnering = turneringsCollection.FindTurnering(turneringsID);
            return (ITurnering)aktuelTurnering;
        }

        public IEnumerator GetTurneringsIterator()
        {
            return turneringsCollection.HentTurneringer();
        }
        #endregion

        #region Deltagere
        public bool TilføjDeltager(string fornavn, string efternavn, string klub, int nr, int rating, double korrektion, int deltagerid = 0)
        {
            if (databaseforbindelse == true)
            {
                if (deltagerid == 0)
                {
                    deltagerID = dbFacade.TilføjDeltager(fornavn, efternavn, klub, nr, rating, korrektion, aktuelTurnering.TurneringsID);
                }
                else
                {
                    deltagerID = deltagerid;
                }

                if (deltagerID != -1)
                {
                    aktuelDeltager = turneringsCollection.TilføjDeltager(aktuelTurnering, fornavn, efternavn, klub, nr, deltagerID, rating, korrektion);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                deltagerID--;
                aktuelDeltager = turneringsCollection.TilføjDeltager(aktuelTurnering, fornavn, efternavn, klub, nr, deltagerID, rating, korrektion);
                return true;
            }
        }

        public IDeltager FindDeltager(int deltagerID)
        {
            aktuelDeltager = turneringsCollection.FindDeltager(aktuelTurnering, deltagerID);
            return (IDeltager)aktuelDeltager;
        }

        public bool FjernDeltager(int deltagerID)
        {
            if (databaseforbindelse == true)
            {
                bool succes = dbFacade.FjernDeltager(deltagerID);
                if (succes == true)
                {
                    turneringsCollection.FjernDeltager(aktuelTurnering, deltagerID);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                turneringsCollection.FjernDeltager(aktuelTurnering, deltagerID);
                return true;
            }
        }

        public bool FlytDeltager(int deltagerID, int nyPlacering)
        {
            if (databaseforbindelse == true)
            {
                bool succes = dbFacade.FlytDeltager(deltagerID, nyPlacering);
                if (succes == true)
                {
                    turneringsCollection.FlytDeltager(aktuelTurnering, deltagerID, nyPlacering);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                turneringsCollection.FlytDeltager(aktuelTurnering, deltagerID, nyPlacering);
                return true;
            }
        }

        public IEnumerator GetDeltagerIterator()
        {
            return aktuelTurnering.GetDeltagerIterator();
        }
        #endregion

        #region Runde
        public bool TilføjRunde(int rundeNr, int modstander, int farve, double resultat, double ialt, int placering, int rundeid = 0)
        {
            if (databaseforbindelse == true)
            {
                if (rundeid == 0)
                {
                    rundeID = dbFacade.TilføjRunde(aktuelDeltager.DeltagerID, rundeNr, modstander, farve, resultat, ialt, placering);
                }
                else
                {
                    rundeID = rundeid;
                }

                if (rundeID != -1)
                {
                    aktuelDeltager.TilføjRunde(rundeNr, modstander, farve, resultat, ialt, placering, rundeID);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                rundeID--;
                aktuelDeltager.TilføjRunde(rundeNr, modstander, farve, resultat, ialt, placering, rundeID);
                return true;
            }
        }

        public bool RedigerRunde(int rundeNr, int modstander, int farve, double resultat, double ialt, int placering)
        {
            aktuelRunde = aktuelDeltager.FindRunde(rundeNr);
            if (databaseforbindelse == true)
            {
                bool succes = dbFacade.RedigerRunde(aktuelRunde.RundeID, rundeNr, modstander, farve, resultat, ialt, placering);
                if (succes == true)
                {
                    aktuelDeltager.RedigerRunde(aktuelRunde, modstander, farve, resultat, ialt, placering);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                aktuelDeltager.RedigerRunde(aktuelRunde, modstander, farve, resultat, ialt, placering);
                return true;
            }
        }

        public IEnumerator GetRundeIterator()
        {
            return aktuelDeltager.GetRundeIterator();
        }
        #endregion

        #region Database
        public bool TestForbindelse()
        {
            if (dbFacade.TestForbindelse() == true)
            {
                databaseforbindelse = true;
                return true;
            }
            else
            {
                databaseforbindelse = false;
                return false;
            }
        }

        public void SetDatabaseStatus(bool status)
        {
            databaseforbindelse = status;
        }

        public void HentDatabase()
        {
            dbFacade.HentDatabase();
        }

        public void SammenlignData()
        {
            FileStream filestream;
            try
            {
                filestream = new FileStream(FILNAVN, FileMode.Open, FileAccess.Read);
            }
            catch (Exception)
            {
                return;
            }
            BinaryFormatter binFormatter = new BinaryFormatter();
            TurneringsCollection midlertidigCollection = (TurneringsCollection)binFormatter.Deserialize(filestream);
            filestream.Close();

            foreach (Turnering midligertidigTurnering in midlertidigCollection.ListeTurneringer)
            {
                if (midligertidigTurnering.TurneringsID < 0)
                {
                    TilføjTurnering(midligertidigTurnering.Turneringsnavn, midligertidigTurnering.Gruppenavn, midligertidigTurnering.Startdato, midligertidigTurnering.AntalRunder);
                    foreach (Deltager midlertidigDeltager in midligertidigTurnering.ListeDeltagere)
                    {
                        TilføjDeltager(midlertidigDeltager.Navn, midlertidigDeltager.Efternavn, midlertidigDeltager.Klub, midlertidigDeltager.Nr, midlertidigDeltager.Rating, midlertidigDeltager.Korrektion);
                        foreach (Runde midlertidigRunde in midlertidigDeltager.ListeRunde)
                        {
                            TilføjRunde(midlertidigRunde.RundeNr, midlertidigRunde.Modstander, midlertidigRunde.Farve, midlertidigRunde.Resultat, midlertidigRunde.Ialt, midlertidigRunde.Placering);
                        }
                    }
                }
            }
        }
        #endregion
    }
}
